package exam;

import java.awt.event.*;

import javax.swing.*;

import java.awt.*;
import java.util.*;
import java.io.*;

import javax.comm.*;

/**
 * Main file for SerialDemo program. This program illustrates many of the
 * abilities of the javax.comm api. This file contains the GUI framework that
 * the program runs in.
 */

public class SerialDemo extends Frame implements ActionListener {

   final int HEIGHT = 423;
   final int WIDTH = 610;

   public Panel southPanel;

   public JButton openButton;
   public JButton closeButton;
   public JButton breakButton;
   public Panel buttonPanel;
   public JButton clearButton;

   public ConfigurationPanel configurationPanel;
   public SerialParameters parameters;
   public SerialConnection connection;
   public ListGUI lg;
   public Properties props = null;
   public ChatGUI cg;
   public static InputStream inputStream;

   /**
    * Main method. Checks to see if the command line argument is requesting
    * usage information (-h, -help), if it is, display a usage message and
    * exit, otherwise create a new <code>SerialDemo</code> and set it visible.
    */
   public static void main() {

      SerialDemo serialDemo = new SerialDemo();
      serialDemo.setVisible(true);
      serialDemo.repaint();
   }

   /**
    * Create new <code>SerialDemo</code> and initializes it. Parses args to
    * find configuration file. If found, initial state it set to parameters in
    * configuration file.
    * 
    * @param args
    *            command line arguments used when program was invoked.
    * @return
    */

   public SerialDemo() {
      super("Serial Demo");

      parameters = new SerialParameters();
      configurationPanel = new ConfigurationPanel(this);
      lg = new ListGUI();
      connection = new SerialConnection(this, parameters);

      buttonPanel = new Panel();
      buttonPanel.setLayout(new GridLayout(4, 1));
      openButton = new JButton("Open Port");
      openButton.addActionListener(this);
      buttonPanel.add(openButton);

      closeButton = new JButton("Close Port");
      closeButton.addActionListener(this);
      closeButton.setEnabled(false);
      buttonPanel.add(closeButton);

      breakButton = new JButton("Comm Start");
      breakButton.addActionListener(this);
      breakButton.setEnabled(false);
      buttonPanel.add(breakButton);

      clearButton = new JButton("Clear Field");
      clearButton.addActionListener(this);
      clearButton.setEnabled(false);
      buttonPanel.add(clearButton);

      southPanel = new Panel();

      GridBagLayout gridBag = new GridBagLayout();
      GridBagConstraints cons = new GridBagConstraints();

      southPanel.setLayout(gridBag);

      cons.gridwidth = GridBagConstraints.REMAINDER;
      gridBag.setConstraints(configurationPanel, cons);
      cons.weightx = 1.0;
      southPanel.add(configurationPanel);
      gridBag.setConstraints(buttonPanel, cons);
      southPanel.add(buttonPanel);

      setConfigurationPanel();

   }

   // Thread-safe way to append to the chat box

   /**
    * Sets the GUI elements on the configurationPanel.
    */
   public void setConfigurationPanel() {
      configurationPanel.setConfigurationPanel();
   }

   /**
    * Responds to the menu items and buttons.
    */

   public void actionPerformed(ActionEvent e) {
      String cmd = e.getActionCommand();

      // Opens a port.
      if (cmd.equals("Open Port")) {
         openButton.setEnabled(false);
         clearButton.setEnabled(true);

         configurationPanel.setParameters();
         try {
            connection.openConnection();
         } catch (SerialConnectionException e2) {
            AlertDialog ad = new AlertDialog(this, "Error Opening Port!",
                  "Error opening port,", e2.getMessage() + ".",
                  "Select new settings, try again.");
            openButton.setEnabled(true);

            return;
         }
         portOpened();
      }

      // Closes a port.
      if (cmd.equals("Close Port")) {
         portClosed();
      }

      // Sends a break signal to the port.
      if (cmd.equals("Comm Start")) {
         connection.sendBreak();
      }

      // clear Field
      if (cmd.equals("Clear Field")) {

      }
   }

   /**
    * Toggles the buttons to an open port state.
    */
   public void portOpened() {
      openButton.setEnabled(false);
      closeButton.setEnabled(true);
      breakButton.setEnabled(true);
   }

   /**
    * Calls closeConnection on the SerialConnection and toggles the buttons to
    * a closed port state.
    */
   public void portClosed() {
      connection.closeConnection();
      openButton.setEnabled(true);
      closeButton.setEnabled(false);
      breakButton.setEnabled(false);
   }

   /**
    * Sets the <code>Cursor</code> for the application.
    * 
    * @param c
    *            New <code>Cursor</code>
    */

   /**
    * Writes the current parameters to a configuration file of the
    * java.properties style.
    */

   /**
    * Finds configuration file in arguments and creates a properties object
    * from that file.
    */

   /**
    * Set the parameters object to the settings in the properties object.
    */
   public void loadParams() {
      parameters.setPortName(props.getProperty("portName"));
      parameters.setBaudRate(props.getProperty("baudRate"));
      parameters.setFlowControlIn(props.getProperty("flowControlIn"));
      parameters.setFlowControlOut(props.getProperty("flowControlOut"));
      parameters.setParity(props.getProperty("parity"));
      parameters.setDatabits(props.getProperty("databits"));
      parameters.setStopbits(props.getProperty("stopbits"));

      setConfigurationPanel();
   }

   /**
    * GUI element that holds the user changable elements for connection
    * configuration.
    */
   class ConfigurationPanel extends Panel implements ItemListener {

      public Frame parent;

      public Label portNameLabel;
      public Choice portChoice;

      public Label baudLabel;
      public Choice baudChoice;

      public Label flowControlInLabel;
      public Choice flowChoiceIn;

      public Label flowControlOutLabel;
      public Choice flowChoiceOut;

      public Label databitsLabel;
      public Choice databitsChoice;

      public Label stopbitsLabel;
      public Choice stopbitsChoice;

      public Label parityLabel;
      public Choice parityChoice;

      /**
       * Creates and initializes the configuration panel. The initial settings
       * are from the parameters object.
       */
      public ConfigurationPanel(Frame parent) {
         this.parent = parent;

         setLayout(new GridLayout(8, 2));

         portNameLabel = new Label("Port Name:", Label.LEFT);
         add(portNameLabel);

         portChoice = new Choice();
         portChoice.addItemListener(this);
         add(portChoice);
         listPortChoices();
         portChoice.select(parameters.getPortName());

         baudLabel = new Label("Baud Rate:", Label.LEFT);
         add(baudLabel);

         baudChoice = new Choice();
         baudChoice.addItem("300");
         baudChoice.addItem("2400");
         baudChoice.addItem("9600");
         baudChoice.addItem("14400");
         baudChoice.addItem("28800");
         baudChoice.addItem("38400");
         baudChoice.addItem("57600");
         baudChoice.addItem("152000");
         baudChoice.select(Integer.toString(parameters.getBaudRate()));
         baudChoice.addItemListener(this);
         add(baudChoice);

         flowControlInLabel = new Label("Flow Control In:", Label.LEFT);
         add(flowControlInLabel);

         flowChoiceIn = new Choice();
         flowChoiceIn.addItem("None");
         flowChoiceIn.addItem("Xon/Xoff In");
         flowChoiceIn.addItem("RTS/CTS In");
         flowChoiceIn.select(parameters.getFlowControlInString());
         flowChoiceIn.addItemListener(this);
         add(flowChoiceIn);

         flowControlOutLabel = new Label("Flow Control Out:", Label.LEFT);
         add(flowControlOutLabel);

         flowChoiceOut = new Choice();
         flowChoiceOut.addItem("None");
         flowChoiceOut.addItem("Xon/Xoff Out");
         flowChoiceOut.addItem("RTS/CTS Out");
         flowChoiceOut.select(parameters.getFlowControlOutString());
         flowChoiceOut.addItemListener(this);
         add(flowChoiceOut);

         databitsLabel = new Label("Data Bits:", Label.LEFT);
         add(databitsLabel);

         databitsChoice = new Choice();
         databitsChoice.addItem("5");
         databitsChoice.addItem("6");
         databitsChoice.addItem("7");
         databitsChoice.addItem("8");
         databitsChoice.select(parameters.getDatabitsString());
         databitsChoice.addItemListener(this);
         add(databitsChoice);

         stopbitsLabel = new Label("Stop Bits:", Label.LEFT);
         add(stopbitsLabel);

         stopbitsChoice = new Choice();
         stopbitsChoice.addItem("1");
         stopbitsChoice.addItem("1.5");
         stopbitsChoice.addItem("2");
         stopbitsChoice.select(parameters.getStopbitsString());
         stopbitsChoice.addItemListener(this);
         add(stopbitsChoice);

         parityLabel = new Label("Parity:", Label.LEFT);
         add(parityLabel);

         parityChoice = new Choice();
         parityChoice.addItem("None");
         parityChoice.addItem("Even");
         parityChoice.addItem("Odd");
         parityChoice.select("None");
         parityChoice.select(parameters.getParityString());
         parityChoice.addItemListener(this);
         add(parityChoice);
      }

      /**
       * Sets the configuration panel to the settings in the parameters
       * object.
       */
      public void setConfigurationPanel() {
         portChoice.select(parameters.getPortName());
         baudChoice.select(parameters.getBaudRateString());
         flowChoiceIn.select(parameters.getFlowControlInString());
         flowChoiceOut.select(parameters.getFlowControlOutString());
         databitsChoice.select(parameters.getDatabitsString());
         stopbitsChoice.select(parameters.getStopbitsString());
         parityChoice.select(parameters.getParityString());
      }

      /**
       * Sets the parameters object to the settings in the configuration
       * panel.
       */
      public void setParameters() {
         parameters.setPortName(portChoice.getSelectedItem());
         parameters.setBaudRate(baudChoice.getSelectedItem());
         parameters.setFlowControlIn(flowChoiceIn.getSelectedItem());
         parameters.setFlowControlOut(flowChoiceOut.getSelectedItem());
         parameters.setDatabits(databitsChoice.getSelectedItem());
         parameters.setStopbits(stopbitsChoice.getSelectedItem());
         parameters.setParity(parityChoice.getSelectedItem());
      }

      /**
       * Sets the elements for the portChoice from the ports available on the
       * system. Uses an emuneration of comm ports returned by
       * CommPortIdentifier.getPortIdentifiers(), then sets the current choice
       * to a mathing element in the parameters object.
       */
      void listPortChoices() {
         CommPortIdentifier portId;

         Enumeration en = CommPortIdentifier.getPortIdentifiers();

         // iterate through the ports.
         while (en.hasMoreElements()) {
            portId = (CommPortIdentifier) en.nextElement();
            if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
               portChoice.addItem(portId.getName());
            }
         }
         portChoice.select(parameters.getPortName());
      }

      /**
       * Event handler for changes in the current selection of the Choices. If
       * a port is open the port can not be changed. If the choice is
       * unsupported on the platform then the user will be notified and the
       * settings will revert to their pre-selection state.
       */
      public void itemStateChanged(ItemEvent e) {
         // Check if port is open.
         if (connection.isOpen()) {
            // If port is open do not allow port to change.
            if (e.getItemSelectable() == portChoice) {
               // Alert user.
               AlertDialog ad = new AlertDialog(parent, "Port Open!",
                     "Port can not", "be changed",
                     "while a port is open.");

               // Return configurationPanel to pre-choice settings.
               setConfigurationPanel();
               return;
            }
            // Set the parameters from the choice panel.
            setParameters();
            try {
               // Attempt to change the settings on an open port.
               connection.setConnectionParameters();
            } catch (SerialConnectionException ex) {
               // If setting can not be changed, alert user, return to
               // pre-choice settings.
               AlertDialog ad = new AlertDialog(parent,
                     "Unsupported Configuration!",
                     "Configuration Parameter unsupported,",
                     "select new value.",
                     "Returning to previous configuration.");
               setConfigurationPanel();
            }
         } else {
            // Since port is not open just set the parameter object.
            setParameters();
         }
      }
   }
}
/**
 * Handles closing down system. Allows application to be closed with window
 * close box.
 */
